feat(albums,artists): browse endpoints for per-library album + artist surface (phase 4.d.0.4) - #36
Conversation
…t surface (phase 4.d.0.4)
Adds 4 read-only endpoints that close the loop on the album / artist
surface materialised by `apply::track` (phase 4.d.0.2) + the schema
shipped in `20260608120000_album_artist.sql` (phase 4.d.0.1):
GET /api/v1/profiles/{p}/libraries/{l}/albums
GET /api/v1/profiles/{p}/libraries/{l}/albums/{id}/tracks
GET /api/v1/profiles/{p}/libraries/{l}/artists
GET /api/v1/profiles/{p}/libraries/{l}/artists/{id}/tracks
Pattern lifts the 2-query ownership-check + fetch idiom from
`db::playlist_track::fetch_for_owner` so 404 (library / album /
artist missing or foreign-owned) stays distinct from 200 [] (owned
but empty). The race window is benign — every parent cascades on
DELETE so a row vanishing between the two queries collapses to the
empty-list answer.
Album list joins `artist` once to surface `album_artist_name` (avoids
N artist lookups client-side). Compilation rows project null +
is_compilation=true. Drill-down ORDER BY rides the indexes the
schema migration planted: album → (disc_number, track_number, id),
artist → (disc_number, track_number, id) via track_artist join.
Writes deliberately not exposed — album / artist rows come from the
apply pipeline only.
TrackResponse gains `album_id` so the artist drill-down can deep-link
contributed tracks to their album page without N extra round-trips.
Existing `/tracks` collection still NULL-projects the column (its
SELECT lives in waveflow-core); follow-up PR bumps core.
Test coverage: empty → 200 [], ordering by updated_at DESC, tied
updated_at → id ASC tiebreak (guards the apply-pipeline-batch
invariant), compilation NULL projection, multi-artist tracks surface
under every contributor, full cross-tenant battery (foreign user,
foreign profile, wrong library_id pivot). OpenAPI snapshot guards
the 4 new paths.
Doc bullet added to server CLAUDE.md.
Signed-off-by: InstaZDLL <github.105mh@8shield.net>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughIntroduction de la Phase 4.d.0.4 : quatre endpoints read-only pour parcourir albums et artistes au sein d'une bibliothèque tenant-scoped, incluant drill-down vers les pistes associées, avec TrackResponse enrichi et validation des scopes composite (profile/library/user). ChangesPhase 4.d.0.4 Browse Surface: Albums et Artistes Read-Only
Sequence Diagram(s)sequenceDiagram
participant Client
participant ListAlbumsHandler as list_albums<br/>Handler
participant db_album as db::album
participant Database
Client->>ListAlbumsHandler: GET /profiles/{profile_id}/libraries/{library_id}/albums
ListAlbumsHandler->>db_album: list_for_library(library_id, profile_id, user_id)
db_album->>Database: SELECT library WHERE id=? AND<br/>profile_id=? AND profile.user_id=?
Database-->>db_album: library_row ou null
db_album->>Database: SELECT album FROM album<br/>WHERE library_id=?<br/>ORDER BY updated_at DESC, id ASC
Database-->>db_album: Vec[AlbumRow]
db_album-->>ListAlbumsHandler: Ok(Some(albums))
ListAlbumsHandler-->>Client: 200 JSON[AlbumResponse]
sequenceDiagram
participant Client
participant ListArtistTracksHandler as list_artist_tracks<br/>Handler
participant db_artist as db::artist
participant Database
Client->>ListArtistTracksHandler: GET /profiles/{profile_id}/libraries/{library_id}/artists/{id}/tracks
ListArtistTracksHandler->>db_artist: list_tracks_for_artist(artist_id, library_id, profile_id, user_id)
db_artist->>Database: SELECT artist WHERE id=? AND<br/>library_id=? AND library.profile_id=?<br/>AND profile.user_id=?
Database-->>db_artist: artist_row ou null
db_artist->>Database: SELECT DISTINCT track FROM track_artist<br/>JOIN track WHERE artist_id=?<br/>AND track.library_id=?<br/>ORDER BY disc_number, track_number
Database-->>db_artist: Vec[TrackRow]
db_artist-->>ListArtistTracksHandler: Ok(Some(tracks))
ListArtistTracksHandler-->>Client: 200 JSON[TrackResponse+album_id]
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/api/mod.rs`:
- Around line 11-12: Mettre à jour le commentaire de module en haut de
src/api/mod.rs pour ne plus qualifier `sync` et `stream` de « Future » :
modifier la phrase "//! Future modules will cover `sync`, `stream` (per RFC-001
§6 / §7)." pour refléter queles modules api::sync et api::stream existent déjà
(ou reformuler en "`sync` and `stream` (per RFC-001 §6 / §7)"); localisez le
commentaire dans le module racine (où api::sync et api::stream sont déclarés) et
remplacez simplement le mot "Future" ou reformulez la phrase sans changer les
noms des modules ni les routes déjà câblées (voir déclarations de modules `sync`
et `stream` et le routeur).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 84e25030-1fcd-49cb-bf22-488fc28677d7
📒 Files selected for processing (9)
CLAUDE.mdsrc/api/albums.rssrc/api/artists.rssrc/api/mod.rssrc/api/tracks.rssrc/db.rstests/albums.rstests/artists.rstests/openapi.rs
CR catch on PR #36: the header still said "Future modules will cover sync, stream" but those modules have been declared + wired into the router since 1.f and 1.e respectively. Refresh the list so it matches what `mod.rs` actually mounts (sync, stream, artwork, share alongside the CRUD modules). @coderabbitai resolved Signed-off-by: InstaZDLL <github.105mh@8shield.net>
|
@coderabbitai resolved in 063ad37 — refreshed the |
|
Tip For best results, initiate chat on the files or code changes.
🧠 Learnings used |
Summary
Closes the loop on phase 4.d.0's chain: the
album/artist/track_artistschema landed in 4.d.0.1 (#34), the apply pipeline started populating it in 4.d.0.2 (#35), the desktop started emitting rows for it in WaveFlow#206 (4.d.0.3) — this PR adds the read endpoints the web client needs to browse what got materialised.Four new endpoints, all read-only, all tenant-scoped behind the existing JWT middleware:
GET /api/v1/profiles/{p}/libraries/{l}/albumsGET /api/v1/profiles/{p}/libraries/{l}/albums/{id}/tracksGET /api/v1/profiles/{p}/libraries/{l}/artistsGET /api/v1/profiles/{p}/libraries/{l}/artists/{id}/tracksKey design choices
Test plan
Coverage
Summary by CodeRabbit
New Features
Documentation
Tests